#ifndef IGSLIB_IACCEPTOR_H
#define IGSLIB_IACCEPTOR_H

#include "igslib_common_use.h"
#include "igslib_iserial_manager.h"
#include "igslib_igpio.h"

namespace igslib
{
    struct IAcceptorEvent;
    struct IMultiSortPath;

    /*!
     * Acceptor泛指投幣器，讀紗機或讀卡機等接收實物裝置。
     *
     * === 注意 ===
     *
     *     以下的說明雖用「幣」為主，但不一定都會是「幣」。
     *     因為投幣器最常見。
     *
     * === 注意 ===
     */
	struct IAcceptor:public IComponent
	{
        enum class ErrorState
        {
            None, //!< 無任何錯誤
            Jammed, //!< 卡幣
            Disconnected, //!< 斷線
            RepeatID, //!< ID重複
            InvalidValue, //!< 不合理值域
        };
        //! 取得目前值。
		virtual float GetValue()=0;
        //! 設定目前值。
		virtual void SetValue(const float&)=0;
        //! 增/減目前值。
		virtual void AddValue(const float&)=0;
        //! 傳回目前錯誤狀態。
		virtual ErrorState GetErrorState()=0;
        /*!
         * 設定錯誤檢查是否啟用。
         * @param a0 false會重置錯誤檢查結果，並關閉錯誤檢查功能，預設為啟用。
         */
		virtual void SetErrorCheck(const bool&)=0;
        //! 傳回錯誤檢查是否啟用。
		virtual bool GetErrorCheck()=0;
        /*!
         * 重置錯誤檢查結果。
         * @note 重置後不會再傳回錯誤，但仍會繼續檢查，若再檢查到錯誤狀態，當然會再傳回錯誤結果。
         */
		virtual void ClearError()=0;
        /*!
         * 設定所有事件的處理者。
         * @param a0 所有事件的處理者。
         */
		virtual void SetEventHandler(IAcceptorEvent*)=0;
        //! 用於更新裝置狀態。
        virtual void Update()=0;
        /*!
         * 設定多少時間內才會確認為真幣，超過此區間範圍的都不會被認定為是真幣。
         * @param a0 最短時間  unit: ms。
         * @param a1 最長時間  unit: ms。
         * @note 時間單位以實作決定。超過區間範圍並不會被認定為是錯誤(卡幣)，除非超過SetJammedTime()設定的時間。
         */
		virtual void SetConfirmRange(const float&,const float&)=0;
        /*!
         * 設定超過多少時間會被認定是卡幣狀態。
         * @param a0 卡幣時間。 unit: ms。
         * @note 時間單位以實作決定。
         */
		virtual void SetJammedTime(const float&)=0;
        /*!
         * 設定是否以high準位認定為進幣訊號。
         * @param a0 true表示要以high準位認定為進幣訊號，預設是以low準位來認定。
         */
		virtual void SetHighActive(const bool&)=0;
        //! 設定是否為全面禁止進幣。
		virtual void SetInhibitiveState(const bool&)=0;
        //! 傳回是否為全面禁止進幣。
		virtual bool GetInhibitiveState()=0;
        /*!
         * 支援多錢道特規的裝置，使用此介面植入實作。
         * @param a0 支援多錢道特規介面之實作。
         */
        virtual void SetMultiSortPath(IMultiSortPath*)=0;
        /*!
         * 支援多錢道特規的裝置，使用此介面取得實作。
         * @return 支援多錢道特規介面之實作。
         */
        virtual IMultiSortPath* GetMultiSortPath()=0;
        /*!
         * 若實作是使用SPI通訊介面，用此函式輸入SPI的實作。
         * @param a0 SPI的實作。
         */
        virtual void SetSPI(ISpi*)=0;
        /*!
         * 若實作是使用GPIO通訊介面，用此函式輸入GPIO的實作。
         * @param a0 GPIO的實作
		 *			-- 投幣器使用板子的接腳。
		 * @param a1 GPIO的實作
		 *          -- 部分投幣器，可以使用禁止投幣功能。
         */
        virtual void SetGPIO(IGPIO*,IGPIO*)=0;
    };

    struct IMultiSortPath
    {
        /*!
         * 註冊一種新的錢道。
         * @param a0 錢道名稱。
         * @param a1 錢道幣值。
         */
        virtual void RegisterSortPath(const std::string&,const float&) = 0;
        /*!
         * 設定錢道是否禁止進幣。
         * @param a0 錢道名稱。
         * @param a1 是否禁止進幣。
         */
        virtual void SetSortPathInhibitState(const std::string&,const bool&) = 0;
        /*!
         * 傳回錢道是否禁止進幣。
         * @param a0 錢道名稱。
         * @return 是否禁止進幣。
         */
        virtual bool GetSortPathInhibitState(const std::string&) = 0;
    };

    struct IAcceptorEvent
    {
        /*!
         * 當目前值有改變的時觸發。
         * @param a0 改變前的值。
         */
        virtual void OnChangeValue(const float&)=0;
        /*!
         * 當任何錯誤發生時觸發。
         * @param a0 發生的錯誤種類。
         */
        virtual void OnErrorRaised(const IAcceptor::ErrorState&)=0;
        /*!
         * 當進幣訊號有在合法範圍內，確認為進幣時觸發。
         * @param a0 進幣訊號時間。
         * @param a1 合法範圍最小值。
         * @param a2 合法範圍最大值。
         */
        virtual void OnInConfirmed(const float&,const float&,const float&)=0;
        /*!
         * 當進幣訊號超過卡幣時間範圍，確認為卡幣時觸發。
         * @param a0 進幣訊號時間。
         * @param a1 卡幣時間設定值。
         */
        virtual void OnJammedConfirmed(const float&,const float&)=0;
        /*!
         * 當目前記錄幣值已經超過合理值域時觸發。
         * @param a0 合法值域最小值。
         * @param a1 合法值域最大值。
         */
        virtual void OnExceedInvalidValue(const float&,const float&)=0;
    };
    struct IAcceptorManager:public IManager<IAcceptor*>
    {
        /*!
         * 創建MH板底通用型投幣器。
         * @return 創建出來的投幣器物件。
         */
        virtual IAcceptor* NewMHAcceptor() = 0;
		/*!
         * 創建MH主板上根據專案特規實作MCU資源。
         * @param a0 專案名。
         * @return 根據專案特規實作MCU資源。
         * @note
         *     目前已實作專案名對照如下：
         *     "DragonBallRace"：龍珠賽球
         *     "DragonWarrior"：鬥龍戰士
         */
        virtual IAcceptor* New_ProjMCU(const std::string&)=0;
    };
};

extern "C"{
    igslib::IAcceptorManager* GetAcceptorManagerInstance();
};


#endif
